<?php

namespace PSC\View;

/**
 * Camada de Visualização
 *
 * Estrutura que busca centralizar as regras de renderização do sistema,
 * centralizando os métodos de captura de conteúdo apresentado na saída padrão
 * para melhor tratamento e renderização em dois passos. Gerenciamento de
 * diretórios para armazenamento de arquivos de renderização.
 *
 * @category PSC
 * @package  PSC\View
 */
class View
{
    /**
     * Caminhos para Busca
     * @var array
     */
    protected $_paths = array();

    /**
     * Parâmetros para Visualização
     * @var array
     */
    protected $_params = array();

    /**
     * Caminhos para Busca de Arquivos
     *
     * Gerenciamento de endereços que podem ser utilizados como caminhos para
     * busca de arquivos do tipo visualização no sistema. Estes são configurados
     * de forma que sempre os últimos caminhos configurados sejam os primeiros a
     * serem processados.
     *
     * @param  string $path Caminho para Inclusão no Sistema de Busca
     * @return View   Próprio Objeto para Encadeamento
     */
    public function addScriptPath($path)
    {
        // Conjunto de Caminhos para Scripts
        if (!array_key_exists('script', $this->_paths)) {
            // Inicialização
            $this->_paths['script'] = array();
        }
        // Conversão
        $path = (string) $path;
        // Configuração
        array_unshift($this->_paths['script'], $path);
        // Encadeamento
        return $this;
    }

    /**
     * Captura de Caminhos para Busca de Arquivos
     *
     * Apresenta todos os caminhos configurados para busca de arquivos na camada
     * de visualização para renderização. Estes caminhos são apresentados de
     * forma contrária à ordem de inclusão.
     *
     * @return array Conjunto de Caminhos Solicitados
     */
    public function getScriptPaths()
    {
        // Resultado Inicial
        $result = array();
        // Verificar Conjunto Inicializado
        if (array_key_exists('script', $this->_paths)) {
            // Capturar Resultado Necessário
            $result = $this->_paths['script'];
        }
        // Apresentação
        return $result;
    }

    /**
     * Configuração de Parâmetros
     *
     * Os parâmetros podem ser consideradoss como valores anexados à camada de
     * visualização e que podem ser utilizados durante uma renderização. Os
     * valores armazenados podem possuir qualquer tipo disponível e não são
     * convertidos. Caso o valor configurado seja nulo, este é retirado do
     * armazenamento da camada.
     *
     * @param  string $name  Nome do Parâmetro para Configuração
     * @param  mixed  $value Valor para Configuração no Parâmetro
     * @return View   Próprio Objeto para Encadeamento
     */
    public function setParam($name, $value)
    {
        // Conversão
        $name = (string) $name;
        // Tipagem de Valor
        if ($value === null) {
            // Remover Parâmetro
            unset($this->_params[$name]);
        } else {
            // Configuração
            $this->_params[$name] = $value;
        }
        // Encadeamento
        return $this;
    }

    /**
     * Captura de Parâmetros
     *
     * Os parâmetros configurados na camada de visualização podem ser capturados
     * utilizando este método, que verifica se o conteúdo foi configurado ou,
     * caso contrário, apresenta um valor nulo na configuração.
     *
     * @param  string $name Nome do Parâmetro Configurado
     * @return mixed  Valor Configurado para o Parâmetro
     */
    public function getParam($name)
    {
        // Conversão
        $name = (string) $name;
        // Resultado Inicial
        $result = null;
        // Verificação
        if ($this->hasParam($name)) {
            // Capturar Valor Armazenado
            $result = $this->_params[$name];
        }
        // Apresentação
        return $result;
    }

    /**
     * Existência de Parâmetro
     *
     * Um parâmetro existe dentro do conjunto de elementos armazenados somente
     * se existe uma entrada neste grupo de valores. Esta entrada somente existe
     * caso os valores configurados sejam diferentes de valores nulos.
     *
     * @param  string $name Nome do Parâmetro para Verificação
     * @return bool   Verificação de Existência do Parâmetro
     */
    public function hasParam($name)
    {
        // Conversão
        $name = (string) $name;
        // Apresentação
        return array_key_exists($name, $this->_params);
    }

   /**
     * Renderização de Conteúdo
     *
     * Um conteúdo pode ser renderizado utilizando os parâmetros configurados
     * para a camada de visualização. Os arquivos utilizados podem possuir
     * processamentos da linguagem e efetuar envio de dados para a saída padrão,
     * que é armazenada utilizando um buffer configurado. O arquivo solicitado é
     * capturado dos diretórios configurados na camada.
     *
     * @param  string $script Arquivo para Renderização
     * @return string Conteúdo Renderizado
     */
    public function render($script)
    {
        // Conteúdo Inicial
        $content = null;
        // Conversão
        $script = (string) $script;
        // Arquivo Encontrado
        $filename = null;
        // Captura do Arquivo
        foreach ($this->getScriptPaths() as $path) {
            // Arquivo Existente no Diretório?
            $filename = realpath($path . DIRECTORY_SEPARATOR . $script);
            // Finalizar Laço de Repetição
            if (!empty($filename)) break;
        }
        // Arquivo Encontrado?
        if (!empty($filename)) {
            // Renderização no Escopo
            ob_start();
            include $filename;
            $content = ob_get_clean();
        }
        // Apresentação
        return $content;
    }

    // Método Mágico: Configuração
    public function __set($name, $value)
    {
        return $this->setParam($name, $value);
    }

    // Método Mágico: Consulta
    public function __get($name)
    {
        return $this->getParam($name);
    }

    // Método Mágico: Desconfiguração
    public function __unset($name)
    {
        return $this->setParam($name, null);
    }

    // Método Mágico: Existência
    public function __isset($name)
    {
        return $this->hasParam($name);
    }

}

